/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of SimpleEL.
 * 
 * SimpleEL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * SimpleEL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with SimpleEL. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.simpleel.speed;

import java.lang.management.*;
import ch.simpleel.data.*;

/**
 * Common parts of the speed test.
 * 
 * @author M. Hautle
 */
public abstract class Common {
    /** The expected values. */
    public static final String[] VALUES = { "Bern", "Switzerland", "Bob", "Baumeister", "-", "Eigerplatz", "8", "3000" };

    /** The properties to check. */
    public static final String[] PROPERTIES = { TheDom.ATTR_CITY, TheDom.ATTR_COUNTRY, TheDom.ATTR_FIRSTNAME, TheDom.ATTR_NAME, TheDom.ATTR_STATE,
            TheDom.ATTR_STREET, TheDom.ATTR_STREET_NUMBER, TheDom.ATTR_ZIP };

    /** The number of calls to execute. */
    private static final int CALLS = 1000000;

    /** The number of runs for {@link #runTest(TheDom, AOtherDom, int)}. */
    private static final int ROUNDS = 10;

    /**
     * Executes the benchmark
     */
    public void executeBenchmark() {
        final TheDom dom = createTheDom();
        final AOtherDom dom2 = createAOtherDom();
        runTest(dom, dom2, ROUNDS, CALLS);
        System.err.println("Real test: " + getClass().getSimpleName());
        runTest(dom, dom2, ROUNDS, CALLS);
        System.err.println("Memory:");
        MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
        System.out.println("Heap: " + mem.getHeapMemoryUsage().getUsed());
        System.out.println("Non Heap: " + mem.getNonHeapMemoryUsage().getUsed());
    }

    private void runTest(TheDom dom, AOtherDom dom2, int rounds, int cnt) {
        long[] res = new long[rounds];
        for (int i = 0; i < rounds; i++)
            res[i] = runTest(dom, dom2, cnt);
        System.out.println("Average: " + getAvg(res));
    }

    private long runTest(TheDom dom, AOtherDom dom2, int cnt) {
        long t = System.currentTimeMillis();
        for (int i = 0; i < cnt;)
            if (executeChecks(dom, dom2))
                i++;
        return System.currentTimeMillis() - t;
    }

    /**
     * Checks the two beans in a specific manner (depending on the benchmark)
     * 
     * @param dom The first bean to check
     * @param dom2 The second bean to check
     * @return True if both were ok
     */
    protected abstract boolean executeChecks(TheDom dom, AOtherDom dom2);

    /**
     * Create and fill an test bean.
     * 
     * @return The dom
     */
    private static TheDom createTheDom() {
        final TheDom d = new TheDom();
        d.setCity("Bern");
        d.setCountry("Switzerland");
        d.setFirstname("Bob");
        d.setName("Baumeister");
        d.setState("-");
        d.setStreet("Eigerplatz");
        d.setStreetNumber("8");
        d.setZip("3000");
        return d;
    }

    /**
     * Create and fill an test bean.
     * 
     * @return The dom
     */
    private static AOtherDom createAOtherDom() {
        final AOtherDom d = new AOtherDom();
        d.setCity("Bern");
        d.setCountry("Switzerland");
        d.setFirstname("Bob");
        d.setName("Baumeister");
        d.setState("-");
        d.setStreet("Eigerplatz");
        d.setStreetNumber("8");
        d.setZip("3000");
        return d;
    }

    /**
     * Computes the average time out of the passed ones.
     * 
     * @param values Timing values
     * @return The average
     */
    private static double getAvg(long[] values) {
        double sum = 0;
        for (long l : values)
            sum += l;
        return sum / values.length;
    }
}
